package com.meeting.meetingroom_api.service.impl;

import com.meeting.meetingroom_api.constants.ErrorMessages;
import com.meeting.meetingroom_api.dto.*;
import com.meeting.meetingroom_api.entity.Booking;
import com.meeting.meetingroom_api.entity.MeetingRoom;
import com.meeting.meetingroom_api.entity.Payment;
import com.meeting.meetingroom_api.entity.User;
import com.meeting.meetingroom_api.enums.BookingStatus;
import com.meeting.meetingroom_api.enums.PaymentStatus;
import com.meeting.meetingroom_api.enums.RoomStatus;
import com.meeting.meetingroom_api.enums.UserRole;
import com.meeting.meetingroom_api.repository.BookingRepository;
import com.meeting.meetingroom_api.repository.MeetingRoomRepository;
import com.meeting.meetingroom_api.repository.PaymentRepository;
import com.meeting.meetingroom_api.repository.UserRepository;
import com.meeting.meetingroom_api.service.BookingService;
import com.meeting.meetingroom_api.service.MeetingRoomService; // For updating room status
import com.meeting.meetingroom_api.service.CancellationService; // Add this import
import com.meeting.meetingroom_api.service.PaymentService; // Add this import
import com.meeting.meetingroom_api.specification.BookingSpecification; // We'll create this
import jakarta.persistence.EntityNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; // 确保导入 @Lazy
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class BookingServiceImpl implements BookingService {

    private final BookingRepository bookingRepository;
    private final UserRepository userRepository;
    private final MeetingRoomRepository meetingRoomRepository;
    private final MeetingRoomService meetingRoomService; // To update meeting room status
    private final PaymentService paymentService; // Add this
    private final PaymentRepository paymentRepository;
    private final CancellationService cancellationService; // Add this
    private static final Logger logger = LoggerFactory.getLogger(BookingServiceImpl.class);

    // Constants
    private static final int MAX_ADVANCE_BOOKING_DAYS = 60;
    private static final int PAYMENT_WINDOW_MINUTES = 30;

    @Autowired
    public BookingServiceImpl(BookingRepository bookingRepository,
                              UserRepository userRepository,
                              MeetingRoomRepository meetingRoomRepository,
                              MeetingRoomService meetingRoomService,
                              PaymentRepository paymentRepository,
                              @Lazy PaymentService paymentService, // 在 PaymentService 参数前添加 @Lazy
                              @Lazy CancellationService cancellationService /* 如果 CancellationService 也参与循环，也添加 @Lazy */) {
        this.bookingRepository = bookingRepository;
        this.userRepository = userRepository;
        this.meetingRoomRepository = meetingRoomRepository;
        this.meetingRoomService = meetingRoomService;
        this.paymentService = paymentService;
        this.cancellationService = cancellationService;
        this.paymentRepository = paymentRepository;
    }

    @Override
    @Transactional
    public BookingDto createBooking(BookingCreateDto createDto, Integer customerId) { // 修改方法签名
        //这里允许一个会议室的不同时间段可以被预定
        //除了判断该预定的时间有没有与会议室开放时间冲突外，还要判断该会议室的其它活跃订单的预订时间有没有与这个预订的时间有冲突，冲突不给预订
        //判断其它活跃pending_payment、confirmed、in_progress的Booking的时间，与这个预订的时间有没有冲突，没有就可以预订。
        //如果没有其它活跃的订单，也就是会议室原本就是空闲的。预订成功后，会议室设为locked。
        User customer = userRepository.findById(customerId) // 使用传入的 customerId
                .orElseThrow(() -> new EntityNotFoundException("Customer not found with ID: " + customerId));
        if (customer.getRole() != UserRole.customer) {
            throw new IllegalArgumentException(ErrorMessages.ONLY_CUSTOMERS_CAN_CREATE_BOOKINGS);
        }
        // Add check for customer account status (active, approved)

        MeetingRoom room = meetingRoomRepository.findById(createDto.getRoomId())
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, createDto.getRoomId())));

        // Validate booking times
        validateBookingTimes(createDto.getStartDatetime(), createDto.getEndDatetime(), room);

        // Validate attendees count
        if (createDto.getAttendeesCount() > room.getCapacity()) {
            throw new IllegalArgumentException(String.format(ErrorMessages.ATTENDEES_EXCEED_CAPACITY, 
                    createDto.getAttendeesCount(), room.getCapacity()));
        }

        // Check for overlapping bookings
        List<BookingStatus> conflictingStatuses = List.of(BookingStatus.confirmed, BookingStatus.pending_payment, BookingStatus.in_progress);
        List<Booking> overlaps = bookingRepository.findOverlappingBookings(room, createDto.getStartDatetime(), createDto.getEndDatetime(), conflictingStatuses);
        if (!overlaps.isEmpty()) {
            throw new IllegalStateException(String.format(ErrorMessages.TIME_SLOT_NOT_AVAILABLE, room.getName()));
        }

        // Check if room is generally available (not maintenance)
        if (room.getStatus() == RoomStatus.maintenance) {
            throw new IllegalStateException(String.format(ErrorMessages.ROOM_UNDER_MAINTENANCE, room.getName()));
        }

//         if (room.getStatus() == RoomStatus.locked || room.getStatus() == RoomStatus.booked || room.getStatus() == RoomStatus.in_use) {
//            // This should ideally be caught by the overlap check, but as a safeguard:
//            throw new IllegalStateException("Room '" + room.getName() + "' is not available for the selected time (status: " + room.getStatus() + ").");
//        }


        Booking booking = new Booking();
        booking.setCustomer(customer);
        booking.setRoom(room);
        booking.setStartDatetime(createDto.getStartDatetime());
        booking.setEndDatetime(createDto.getEndDatetime());
        booking.setAttendeesCount(createDto.getAttendeesCount());
        booking.setEquipmentRequired(createDto.getEquipmentRequired());

        // Calculate total price
        long hours = Duration.between(createDto.getStartDatetime(), createDto.getEndDatetime()).toHours();
        if (hours <= 0) { // Should be caught by validation, but as a safeguard
            throw new IllegalArgumentException(ErrorMessages.BOOKING_DURATION_MIN_ONE_HOUR);
        }
        booking.setTotalPrice(room.getPricePerHour().multiply(BigDecimal.valueOf(hours)));

        booking.setStatus(BookingStatus.pending_payment);
        booking.setPaymentDeadline(LocalDateTime.now().plusMinutes(PAYMENT_WINDOW_MINUTES));

        Booking savedBooking = bookingRepository.save(booking);

        // Create initial payment record
        paymentService.createInitialPaymentRecord(savedBooking);

        // 注释：会议室状态现在只通过计算得出，不再直接设置为locked
        // meetingRoomService.updateMeetingRoomStatus(room.getRoomId(), RoomStatus.locked);
        
        return convertToDto(savedBooking);
    }

    private void validateBookingTimes(LocalDateTime start, LocalDateTime end, MeetingRoom room) {
        if (start == null || end == null) {
            throw new IllegalArgumentException(ErrorMessages.START_END_TIMES_CANNOT_BE_NULL);
        }
        if (!end.isAfter(start)) {
            throw new IllegalArgumentException(ErrorMessages.END_TIME_MUST_AFTER_START);
        }
        if (start.getMinute() != 0 || start.getSecond() != 0 || end.getMinute() != 0 || end.getSecond() != 0) {
            throw new IllegalArgumentException(ErrorMessages.BOOKING_TIMES_MUST_ON_HOUR);
        }
        if (Duration.between(start, end).toHours() < 1) {
            throw new IllegalArgumentException(ErrorMessages.MINIMUM_BOOKING_DURATION);
        }
//        //去掉或者改成限制为8:00~21:00
//        if (start.toLocalTime().isBefore(room.getOperatingStartTime()) || end.toLocalTime().isAfter(room.getOperatingEndTime())) {
//            throw new IllegalArgumentException("Booking times must be within room operating hours (" +
//                    room.getOperatingStartTime() + " - " + room.getOperatingEndTime() + ").");
//        }

        // 限制预约时间为 08:00~21:00（业务要求硬编码）
        LocalTime minStartTime = LocalTime.of(8, 0);
        LocalTime maxEndTime = LocalTime.of(21, 0);

        if (start.toLocalTime().isBefore(minStartTime) || end.toLocalTime().isAfter(maxEndTime)) {
            throw new IllegalArgumentException("预约时间必须在 08:00~21:00 之间");
        }

        if (start.isBefore(LocalDateTime.now())) {
            throw new IllegalArgumentException(ErrorMessages.CANNOT_BOOK_PAST_TIME);
        }
        if (start.isAfter(LocalDateTime.now().plusDays(MAX_ADVANCE_BOOKING_DAYS))) {
            throw new IllegalArgumentException(String.format(ErrorMessages.BOOKING_ADVANCE_LIMIT, MAX_ADVANCE_BOOKING_DAYS));
        }
    }


    @Override
    public BookingDto getBookingById(Integer bookingId) {
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("Booking not found with ID: " + bookingId));
        return convertToDto(booking);
    }

    @Override
    public BookingDto getTimeOutBookById(Integer bookingId) {
        Booking booking = bookingRepository.findById(bookingId)
                .orElse(null);
        if (booking == null) return null;
        return convertToDto(booking);
    }

    @Override
    public BookingDto getBookingByIdAndCustomerId(Integer bookingId, Integer customerId) {
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("Customer not found with ID: " + customerId));
        Booking booking = bookingRepository.findByBookingIdAndCustomer(bookingId, customer)
                .orElseThrow(() -> new EntityNotFoundException("Booking not found with ID: " + bookingId + " for this customer."));
        return convertToDto(booking);
    }

    @Override
    public Page<BookingDto> findBookings(BookingQueryDto queryDto, Pageable pageable) {
        // 时间范围验证
        if (queryDto.getStartDatetime() != null && queryDto.getEndDatetime() != null) {
            if (!queryDto.getEndDatetime().isAfter(queryDto.getStartDatetime())) {
                throw new IllegalArgumentException("结束时间必须晚于开始时间");
            }
        }
        
        Specification<Booking> spec = BookingSpecification.findByCriteria(queryDto);
        Page<Booking> bookingsPage = bookingRepository.findAll(spec, pageable);
        return bookingsPage.map(this::convertToDto);
    }

    @Override
    public List<BookingDto> getBookingsByCustomerId(Integer customerId) {
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("Customer not found with ID: " + customerId));
        return bookingRepository.findByCustomer(customer).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public Page<BookingDto> getBookingsByCustomerId(BookingStatus status, Integer customerId, Pageable pageable) {
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("Customer not found with ID: " + customerId));
        // 根据客户ID和状态查询订单
        Page<Booking> bookings;
        if (status != null) {
            // 如果提供了状态，按客户和状态查询
            bookings = bookingRepository.findByCustomerAndStatus(customer, status, pageable);
        } else {
            // 如果未提供状态，只按客户查询（原逻辑）
            bookings = bookingRepository.findByCustomer(customer, pageable);
        }
        return bookings.map(this::convertToDto);
    }

    @Override
    public List<BookingDto> getBookingsByRoomId(Integer roomId) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));
        return bookingRepository.findByRoom(room).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public Page<BookingDto> getBookingsByRoomId(Integer roomId, Pageable pageable) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));
        Page<Booking> bookings = bookingRepository.findByRoom(room, pageable);
        return bookings.map(this::convertToDto);
    }

    @Override
    @Transactional
    public BookingDto updateBookingStatus(Integer bookingId, BookingStatus newStatus, Integer employeeIdIfApplicable) {
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("Booking not found with ID: " + bookingId));

        // Add logic for who can change to what status (e.g., employee for IN_PROGRESS/COMPLETED)
        // For example, if newStatus is IN_PROGRESS, an employee must be involved.
        if (employeeIdIfApplicable != null) {
            User employee = userRepository.findById(employeeIdIfApplicable)
                    .orElseThrow(() -> new EntityNotFoundException("Employee not found with ID: " + employeeIdIfApplicable));
            if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) { // Changed to lowercase
                throw new IllegalArgumentException(ErrorMessages.ONLY_EMPLOYEES_ADMINS_CAN_UPDATE_STATUS);
            }
            // Log employee action if necessary
        }

        BookingStatus oldStatus = booking.getStatus();
        booking.setStatus(newStatus); // newStatus is already a parameter, assumed to be lowercase if passed correctly

        // 注释：会议室状态现在只通过计算得出，不再直接设置
        // MeetingRoom room = booking.getRoom();
        // if (oldStatus == BookingStatus.pending_payment && newStatus == BookingStatus.confirmed) {
        //     meetingRoomService.updateMeetingRoomStatus(room.getRoomId(), RoomStatus.booked);
        // } else if (newStatus == BookingStatus.in_progress) {
        //     meetingRoomService.updateMeetingRoomStatus(room.getRoomId(), RoomStatus.in_use);
        // } else if (newStatus == BookingStatus.completed ||
        //         newStatus == BookingStatus.cancelled_by_customer ||
        //         newStatus == BookingStatus.cancelled_payment_timeout) {
        //     // Check if there are other confirmed/pending bookings for this room before setting to AVAILABLE
        //     List<BookingStatus> activeStatuses = List.of(BookingStatus.confirmed, BookingStatus.pending_payment, BookingStatus.in_progress);
        //     boolean hasOtherActiveBookings = bookingRepository.findOverlappingBookings(room, booking.getStartDatetime(), booking.getEndDatetime(), activeStatuses)
        //             .stream().anyMatch(b -> !b.getBookingId().equals(bookingId));
        //     if (!hasOtherActiveBookings) {
        //         // 检查是否有其他活跃的预订（使用时间过滤查询）
        //         boolean roomStillOccupied = bookingRepository.existsByRoomAndStatusInAndNotExpired(room,
        //                 List.of(BookingStatus.confirmed, BookingStatus.pending_payment, BookingStatus.in_progress));
        //
        //         if (!roomStillOccupied) {
        //             meetingRoomService.updateMeetingRoomStatus(room.getRoomId(), RoomStatus.available);
        //         }
        //     }
        // }
        // Add more transitions as needed (e.g., from BOOKED to IN_PROGRESS by employee)

        Booking updatedBooking = bookingRepository.save(booking);
        return convertToDto(updatedBooking);
    }

    // Scheduled task method (e.g., run every few minutes)
    // @Scheduled(fixedRate = 5 * 60 * 1000) // Every 5 minutes
    @Transactional
    public void processPaymentTimeoutBookings() {
        List<Booking> timedOutBookings = bookingRepository.findByStatusAndPaymentDeadlineBefore(
                BookingStatus.pending_payment, LocalDateTime.now()); // Changed to lowercase

        for (Booking booking : timedOutBookings) {
            // booking.setStatus(BookingStatus.cancelled_payment_timeout); // This will be handled by cancellationService
            // bookingRepository.save(booking); // This will be handled by cancellationService

            // Record system cancellation
            // For payment timeout, typically no refund and no fee if payment wasn't made.
            cancellationService.systemCancellation(booking, "Payment deadline passed.");

            // Make the room available again if no other active bookings for that slot
            // This logic is now part of bookingService.updateBookingStatus, which is called by cancellationService
            // MeetingRoom room = booking.getRoom();
            // meetingRoomService.updateMeetingRoomStatus(room.getRoomId(), MeetingRoomStatus.available); // Changed to lowercase

            System.out.println("Booking ID " + booking.getBookingId() + " cancelled due to payment timeout.");
        }
    }

    @Override
    public Page<BookingDto> getCancellableBookingsByCustomerId(Integer customerId, Pageable pageable) {
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("Customer not found with ID: " + customerId));

        LocalDateTime minStartTime = LocalDateTime.now().plusHours(24); // 至少24小时后的预订

        // 使用 Specification 构建查询条件
        Specification<Booking> spec = (root, query, cb) -> {
            return cb.and(
                    cb.equal(root.get("customer"), customer),
                    cb.equal(root.get("status"), BookingStatus.confirmed),
                    cb.greaterThan(root.get("startDatetime"), minStartTime)
            );
        };

        Page<Booking> bookings = bookingRepository.findAll(spec, pageable);
        return bookings.map(this::convertToDto);
    }

    @Override
    @Transactional
    public BookingDto setRoomMaintenance(Integer bookingId, Integer employeeId, String maintenanceNotes) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有设置维护状态的权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证预订状态
        if (booking.getStatus() != BookingStatus.completed) {
            throw new IllegalStateException("只能为已完成的预订设置维护状态");
        }

        // 更新会议室状态
        MeetingRoom room = booking.getRoom();
        room.setStatus(RoomStatus.maintenance);
        room.setDescription(maintenanceNotes); // 将维护说明添加到会议室描述中
        meetingRoomRepository.save(room);

        // 更新预订信息
        booking.setRoomConditionNotes(maintenanceNotes);
        booking.setCheckedBy(employee);
        booking.setUpdatedAt(LocalDateTime.now());

        return convertToDto(bookingRepository.save(booking));
    }

    @Override
    @Transactional
    public BookingDto completeMaintenance(Integer bookingId, Integer employeeId) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有完成维护的权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证会议室状态
        MeetingRoom room = booking.getRoom();
        if (room.getStatus() != RoomStatus.maintenance) {
            throw new IllegalStateException("会议室不在维护状态");
        }

        // 更新会议室状态
        room.setStatus(RoomStatus.available);
        room.setDescription(room.getDescription() + "\n维护完成时间：" + LocalDateTime.now());
        meetingRoomRepository.save(room);

        // 更新预订信息
        booking.setRoomConditionNotes(booking.getRoomConditionNotes() + "\n维护完成 - 确认人：" + employee.getFullName());
        booking.setCheckedBy(employee);
        booking.setUpdatedAt(LocalDateTime.now());

        return convertToDto(bookingRepository.save(booking));
    }

    //根据已被预订或使用中的会议室id查询对应订单信息、逻辑改变了，用不上了
    @Override
    public BookingDto getBookingByActiveRoomId(Integer roomId) {
        BookingQueryDto queryDto = new BookingQueryDto();
        queryDto.setRoomId(roomId);
        queryDto.setStatusList(Arrays.asList(BookingStatus.confirmed, BookingStatus.in_progress));
        // 执行查询，取第一条结果
        Specification<Booking> spec = BookingSpecification.findByCriteria(queryDto);
        Booking activeBooking = bookingRepository.findOne(spec)
                .orElse(null);
        return convertToDto(activeBooking);
    }

    @Override
    public Page<BookingDto> getCompletedBookings(Integer id, Pageable pageable) {
        User customer = userRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("Customer not found with ID: " + id));
        // 根据客户ID和状态查询订单
        List<BookingStatus> statuses = Arrays.asList(BookingStatus.completed, BookingStatus.cancelled_by_customer
                , BookingStatus.cancelled_payment_timeout);
        Page<Booking> bookings = bookingRepository.findByCustomerAndStatusIn(customer, statuses, pageable);
        return bookings.map(this::convertToDto);
    }

    /**
     * 客户取消待支付的订单（pending_payment -> cancelled_by_customer）
     */
    //取消后，查询其它活跃订单，同时改变对应会议室状态。
    @Override
    @Transactional
    public BookingDto cancelPendingPay(Integer bookingId) {
        // 1. 查询待支付订单
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("Booking not found with ID: " + bookingId));

        // 2. 验证订单状态（必须是pending_payment才能取消）
        if (booking.getStatus() != BookingStatus.pending_payment) {
            throw new IllegalStateException(ErrorMessages.ONLY_PENDING_PAYMENT_CAN_BE_CANCELLED);
        }
        else{
            //修改支付表的状态failed
            Payment payment=booking.getPayment();
            payment.setStatus(PaymentStatus.failed);
            paymentRepository.save(payment);
        }
        // 3. 查询该会议室是否存在其他活跃订单（pending_payment,confirmed, in_progress）
        MeetingRoom room = booking.getRoom();

        // 4. 更新订单状态
        booking.setStatus(BookingStatus.cancelled_by_customer);
        booking.setUpdatedAt(LocalDateTime.now());

        // 5. 如果没有其他活跃订单，释放会议室资源（将状态改为available）
        // 查询该会议室的活跃订单（排除当前订单）

        List<BookingStatus> activeStatuses = Arrays.asList(
                BookingStatus.pending_payment,
                BookingStatus.confirmed,
                BookingStatus.in_progress
        );
        //查询具体活跃订单，改变会议室对应状态
        List<Booking> activeBookings = bookingRepository.findByRoomRoomIdAndStatusInAndBookingIdNotAndNotExpired(
                room.getRoomId(),
                activeStatuses,
                bookingId // 排除当前订单（当前订单ID）
        );
        // 注释：会议室状态现在只通过计算得出，不再直接设置
        // RoomStatus newStatus = determineRoomStatus(activeBookings);
        // if (room.getStatus() != RoomStatus.maintenance) {
        // room.setStatus(newStatus);
        // }
        // meetingRoomRepository.save(room);
        // 6. 保存更新并返回
        Booking updatedBooking = bookingRepository.save(booking);
        return convertToDto(updatedBooking);
    }

    //查找前5分钟超时的订单，扩大处理的范围
    @Override
    public List<Booking> findByStatusAndPaymentDeadlineBetween(BookingStatus bookingStatus, LocalDateTime fiveMinutesAgo, LocalDateTime now) {
        return bookingRepository.findByStatusAndPaymentDeadlineBetween(bookingStatus, fiveMinutesAgo, now);
    }

    //处理超时订单
    @Transactional
    @Override
    public void handleTimeOut(Booking booking) {
        // 先刷新获取最新状态
        Booking managedBooking = bookingRepository.findById(booking.getBookingId())
                .orElse(null);
        if (managedBooking == null) return;
        Payment payment = managedBooking.getPayment();
        if (payment != null && payment.getStatus() == PaymentStatus.pending) {
            // 更新支付状态
            payment.setStatus(PaymentStatus.failed);
            paymentRepository.save(payment);
        }

        if (managedBooking.getStatus() == BookingStatus.pending_payment) {
            // 更新订单状态
            managedBooking.setStatus(BookingStatus.cancelled_payment_timeout);
            bookingRepository.save(managedBooking);
        }
        // 查询该会议室的活跃订单（排除当前订单）
        List<BookingStatus> activeStatuses = Arrays.asList(
                BookingStatus.pending_payment,
                BookingStatus.confirmed,
                BookingStatus.in_progress
        );
        MeetingRoom room = managedBooking.getRoom();
        //查询具体活跃订单，改变会议室对应状态
        List<Booking> activeBookings = bookingRepository.findByRoomRoomIdAndStatusInAndBookingIdNotAndNotExpired(
                room.getRoomId(),
                activeStatuses,
                managedBooking.getBookingId() // 排除当前订单（当前订单ID）
        );
        // 注释：会议室状态现在只通过计算得出，不再直接设置
        // RoomStatus newStatus = determineRoomStatus(activeBookings);
        // if (room.getStatus() != RoomStatus.maintenance && newStatus != room.getStatus()) {
        //     room.setStatus(newStatus);
        //     meetingRoomRepository.save(room);
        // }
    }

    @Override
    public List<Booking> findExpiredBookings() {
        return bookingRepository.findExpiredActiveBookings(
                BookingStatus.confirmed,
                BookingStatus.in_progress,
                LocalDateTime.now()
        );
    }

    @Override
    @Transactional
    public void handleExpiredBooking(Booking booking) {
        try {
            // 获取最新的预订信息
            Booking managedBooking = bookingRepository.findById(booking.getBookingId())
                    .orElse(null);
            if (managedBooking == null) {
                return;
            }

            // 检查是否真的过期了
            if (managedBooking.getEndDatetime().isAfter(LocalDateTime.now())) {
                return; // 没有过期，跳过
            }

            BookingStatus oldStatus = managedBooking.getStatus();

            // 只处理confirmed和in_progress状态的过期预订
            if (oldStatus == BookingStatus.confirmed || oldStatus == BookingStatus.in_progress) {
                // 更新预订状态为completed
                managedBooking.setStatus(BookingStatus.completed);

                // 如果是in_progress状态但没有checkout时间，设置自动checkout时间
                if (oldStatus == BookingStatus.in_progress && managedBooking.getCheckOutTime() == null) {
                    managedBooking.setCheckOutTime(managedBooking.getEndDatetime());
                    managedBooking.setRoomConditionNotes("系统自动完成 - 预订时间已结束");
                }

                bookingRepository.save(managedBooking);

                // 更新会议室状态
                updateRoomStatusAfterBookingCompletion(managedBooking);

                logger.info("过期预订已处理: bookingId={}, oldStatus={}, newStatus=completed",
                        managedBooking.getBookingId(), oldStatus);
            }
        } catch (Exception e) {
            logger.error("处理过期预订时发生错误: bookingId={}", booking.getBookingId(), e);
        }
    }

    @Override
    @Transactional
    public void processExpiredBookings() {
        try {
            List<Booking> expiredBookings = findExpiredBookings();
            logger.info("发现 {} 个过期预订需要处理", expiredBookings.size());

            for (Booking booking : expiredBookings) {
                handleExpiredBooking(booking);
            }

            if (!expiredBookings.isEmpty()) {
                logger.info("完成处理 {} 个过期预订", expiredBookings.size());
            }
        } catch (Exception e) {
            logger.error("批量处理过期预订时发生错误", e);
        }
    }

    /**
     * 预订完成后更新会议室状态
     */
    private void updateRoomStatusAfterBookingCompletion(Booking completedBooking) {
        try {
            MeetingRoom room = completedBooking.getRoom();

            // 检查该会议室是否还有其他活跃的预订
            boolean hasActiveBookings = checkActiveBookingsForRoom(
                    room.getRoomId(),
                    completedBooking.getBookingId()
            );

            // 注释：会议室状态现在只通过计算得出，不再直接设置为available
            // if (!hasActiveBookings && room.getStatus() != RoomStatus.maintenance) {
            //     room.setStatus(RoomStatus.available);
            //     meetingRoomRepository.save(room);
            //     logger.info("会议室状态已更新为available: roomId={}", room.getRoomId());
            // }
        } catch (Exception e) {
            logger.error("更新会议室状态时发生错误: roomId={}",
                    completedBooking.getRoom().getRoomId(), e);
        }
    }

    @Override
    @Transactional
    public BookingDto checkIn(Integer bookingId, Integer employeeId) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有入场登记权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证预订状态
        if (booking.getStatus() != BookingStatus.confirmed) {
            throw new IllegalStateException("只能为已确认的预订进行入场登记");
        }

        // 验证时间
        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(booking.getStartDatetime().minusMinutes(30))) {
            throw new IllegalStateException("距离预订开始时间还有30分钟以上，不能提前入场");
        }
        if (now.isAfter(booking.getEndDatetime())) {
            throw new IllegalStateException("预订时间已过，不能入场");
        }

        // 更新预订状态
        booking.setStatus(BookingStatus.in_progress);
        booking.setCheckInTime(now);
        booking.setCheckedBy(employee);

        // 检查会议室维护状态
        MeetingRoom room = booking.getRoom();
        if (room.getStatus() == RoomStatus.maintenance) {
            // 如果会议室在维护中，不允许入场
            throw new IllegalStateException(ErrorMessages.ROOM_IN_MAINTENANCE_CANNOT_CHECKIN);
        }
        
        // 注释：会议室状态现在只通过计算得出，不再直接设置为in_use
        // room.setStatus(RoomStatus.in_use);
        // meetingRoomRepository.save(room);

        return convertToDto(bookingRepository.save(booking));
    }
    //TODO: 强制维修？
    @Override
    @Transactional
    public BookingDto checkOut(Integer bookingId, Integer employeeId, String roomConditionNotes) {
        //该订单in_progress->completed，允许员工根据实际情况设置维护状态

        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有离场登记权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证预订状态
        if (booking.getStatus() != BookingStatus.in_progress) {
            throw new IllegalStateException("只能为使用中的预订进行离场登记");
        }

        MeetingRoom room = booking.getRoom();

        // 更新预订状态
        booking.setStatus(BookingStatus.completed);
        booking.setCheckOutTime(LocalDateTime.now());
        booking.setCheckedBy(employee);

        // 根据房间状况设置维护状态 - 员工可以根据实际情况设置维护状态
        if (roomConditionNotes != null && !roomConditionNotes.trim().isEmpty()) {
            // 有房间状况备注，设置为维护状态
            room.setDescription(roomConditionNotes);
            room.setStatus(RoomStatus.maintenance);
            booking.setRoomConditionNotes(roomConditionNotes);
            // 更新会议室状态
            meetingRoomRepository.save(room);
        } else if (room.getStatus() == RoomStatus.maintenance) {
            // 会议室已在维护中，保持维护状态
            booking.setRoomConditionNotes("会议室仍在维护中");
        } else {
            // 注释：会议室状态现在只通过计算得出，不再直接设置
            // boolean hasActiveBookings = checkActiveBookingsForRoom(room.getRoomId(), bookingId);
            // if (!hasActiveBookings) {
            //     room.setStatus(RoomStatus.available);
            // } else {
            //     // 查询该会议室的活跃订单（排除当前订单）
            //     List<BookingStatus> activeStatuses = Arrays.asList(
            //             BookingStatus.pending_payment,
            //             BookingStatus.confirmed,
            //             BookingStatus.in_progress
            //     );
            //     List<Booking> activeBookings = bookingRepository.findByRoomRoomIdAndStatusInAndBookingIdNotAndNotExpired(
            //             room.getRoomId(),
            //             activeStatuses,
            //             bookingId // 排除当前订单（当前订单ID）
            //     );
            //     // 根据优先级设置会议室状态
            //     RoomStatus newStatus = determineRoomStatus(activeBookings);
            //     room.setStatus(newStatus);
            // }
            
            // 设置默认备注说明状态正常
            if (booking.getRoomConditionNotes() == null || booking.getRoomConditionNotes().trim().isEmpty()) {
                booking.setRoomConditionNotes("设备状况正常");
            }
        }

        return convertToDto(bookingRepository.save(booking));
    }

    /**
     * 检查会议室是否存在其他活跃订单（pending_payment、confirmed 或 in_progress）
     */
    private boolean checkActiveBookingsForRoom(Integer roomId, Integer currentBookingId) {
        List<BookingStatus> activeStatuses = Arrays.asList(BookingStatus.confirmed, BookingStatus.in_progress,
                BookingStatus.pending_payment);

        // 查询该会议室下状态为confirmed或in_progress且ID不等于当前订单的订单数量（使用时间过滤）
        long count = bookingRepository.countByRoomRoomIdAndStatusInAndBookingIdNotAndNotExpired(
                roomId,
                activeStatuses,
                currentBookingId
        );

        return count > 0;
    }

    //查询订单状态，改变对应会议室状态。
    private RoomStatus determineRoomStatus(List<Booking> activeBookings) {
        // 优先级：pending_payment > in_progress > confirmed
        if (activeBookings.stream().anyMatch(b -> b.getStatus() == BookingStatus.pending_payment)) {
            return RoomStatus.locked;
        } else if (activeBookings.stream().anyMatch(b -> b.getStatus() == BookingStatus.in_progress)) {
            return RoomStatus.in_use;
        } else if (activeBookings.stream().anyMatch(b -> b.getStatus() == BookingStatus.confirmed)) {
            return RoomStatus.booked;
        } else {
            return RoomStatus.available;
        }
    }

    private BookingDto convertToDto(Booking booking) {
        BookingDto dto = new BookingDto();
        BeanUtils.copyProperties(booking, dto);
        if (booking.getCustomer() != null) {
            dto.setCustomerId(booking.getCustomer().getUserId());
            dto.setCustomerName(booking.getCustomer().getUsername());
        }
        if (booking.getCheckedBy() != null) {
            dto.setCheckedById(booking.getCheckedBy().getUserId());
            dto.setCheckedByName(booking.getCheckedBy().getUsername());
        }
        // 现在都允许设置维护状态，不再需要失败标记
        dto.setFailed(false);
        if (booking.getRoom() != null) {
            dto.setRoomId(booking.getRoom().getRoomId());
            dto.setRoomName(booking.getRoom().getName());
        }
        return dto;
    }
}
